package in.rob.client.dialog.base;
import android.app.AlertDialog;
import android.app.AlertDialog.Builder;
import android.content.DialogInterface;
import android.content.DialogInterface.OnClickListener;
import android.content.Intent;
import android.database.Cursor;
import android.location.Location;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
import android.provider.MediaStore;
import android.text.Editable;
import android.text.InputType;
import android.text.Spannable;
import android.text.SpannableStringBuilder;
import android.text.TextUtils;
import android.text.TextWatcher;
import android.text.style.ClickableSpan;
import android.view.LayoutInflater;
import android.view.MenuItem;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.HorizontalScrollView;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.PopupMenu;
import android.widget.PopupMenu.OnMenuItemClickListener;
import android.widget.TextView;
import android.widget.Toast;
import com.nostra13.universalimageloader.core.ImageLoader;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import in.data.annotation.FileAnnotation;
import in.data.annotation.LocationAnnotation;
import in.data.entity.Entity;
import in.data.entity.LinkEntity;
import in.lib.Constants;
import in.lib.adapter.AccountAdapter;
import in.lib.adapter.AutoCompleteAdapter;
import in.lib.builder.DialogBuilder;
import in.lib.helper.LocationHelper;
import in.lib.helper.LocationHelper.Accuracy;
import in.lib.helper.LocationHelper.LocationResponse;
import in.lib.manager.CacheManager;
import in.lib.manager.UserManager;
import in.lib.type.TListWrapper;
import in.lib.utils.Debug;
import in.lib.utils.Regex;
import in.lib.utils.SpaceTokenizer;
import in.lib.utils.Views;
import in.lib.utils.Views.InjectView;
import in.lib.utils.Views.Injectable;
import in.lib.utils.Views.OnClick;
import in.lib.view.AutoSuggestView;
import in.lib.view.AvatarImageView;
import in.lib.view.LinkedAutoCompleteTextView;
import in.lib.view.LinkedAutoCompleteTextView.OnSpannableClickedListener;
import in.lib.view.spannable.MarkDownClickableSpan;
import in.model.AdnModel;
import in.model.SimpleUser;
import in.model.User;
import in.model.base.Draft;
import in.rob.client.AuthenticationActivity;
import in.rob.client.R;
import in.rob.client.StorageBrowserActivity;
import lombok.Getter;
import lombok.Setter;
@Injectable
public abstract class InputPostDialog extends PostDialog
{
@Getter @InjectView private View positiveButton;
@Getter @InjectView private View negativeButton;
@Getter @InjectView private TextView postInput;
@Getter @InjectView private TextView counter;
@Getter @InjectView private LinearLayout imageContainer;
@Getter @InjectView private ImageButton actionImage;
@Getter @InjectView private ImageButton actionLocation;
@Getter @InjectView private AvatarImageView actionAccount;
@InjectView private TextView title;
@Getter private LocationHelper locationHelper;
@Getter @Setter private Draft draft;
@Getter @Setter private int maxChars = 256;
private boolean finish = false;
@Getter private AutoCompleteAdapter adapter;
private Uri tempImagePath;
@Override protected void onCreate(Bundle savedInstanceState)
{
initialiseDraft();
super.onCreate(savedInstanceState);
Views.inject(this);
locationHelper = new LocationHelper(getContext());
initialiseDialog();
}
@Override public int getContentView()
{
return R.layout.post_dialog;
}
@Override public void onBackPressed()
{
onNegativeButtonClick(negativeButton);
}
@Override public void setTitle(int res)
{
this.title.setText(res);
}
@Override public void setTitle(CharSequence title)
{
this.title.setText(title);
}
/**
* Override this method to create the draft
*/
public abstract void initialiseDraft();
public void initialiseDialog()
{
final Pattern mdLinkMatcher = Pattern.compile("\\[([^\\]]+)\\]\\(([^)]+)\\)", Pattern.CASE_INSENSITIVE);
final TextWatcher textWatcher = new TextWatcher()
{
@Override public void beforeTextChanged(CharSequence s, int start, int count, int after){}
@Override public void onTextChanged(CharSequence s, int start, int before, int count)
{
Matcher matcher = mdLinkMatcher.matcher(s);
while (matcher.find())
{
String match = matcher.group();
String link = matcher.group(2);
String anchor = matcher.group(1).trim();
if (Regex.REGEX_URL.matcher(link).find())
{
int pos = s.toString().indexOf(match);
SpannableStringBuilder newLink = new SpannableStringBuilder(anchor);
newLink.setSpan(new MarkDownClickableSpan(link, anchor), 0, anchor.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
SpannableStringBuilder newText = new SpannableStringBuilder(s);
newText.replace(pos, pos + match.length(), newLink);
newText.append(' ');
getPostInput().setText(newText);
((EditText)getPostInput()).setSelection(getPostInput().getText().length());
}
}
}
@Override public void afterTextChanged(Editable s)
{
MarkDownClickableSpan[] links = s.getSpans(0, s.length(), MarkDownClickableSpan.class);
for (MarkDownClickableSpan l : links)
{
int spanStart = s.getSpanStart(l);
int spanEnd = s.getSpanEnd(l);
int anchorLen = l.getAnchor().length();
int newLen = spanEnd - spanStart;
if (newLen < anchorLen)
{
String spanText = s.subSequence(spanStart, spanEnd).toString().substring(0, newLen);
s.removeSpan(l);
if (l.getAnchor().startsWith(spanText))
{
s.replace(spanStart, spanStart + spanText.length(), "[" + l.getAnchor() + "](" + l.getUrl());
}
}
}
int remaining = maxChars - getPostInput().getText().toString().trim().length();
setRemainingChars(remaining);
}
};
getPostInput().addTextChangedListener(textWatcher);
if (getPostInput() instanceof AutoSuggestView)
{
List<SimpleUser> items = new ArrayList<SimpleUser>();
adapter = new AutoCompleteAdapter(getContext(), items);
((AutoSuggestView)getPostInput()).setAdapter(adapter);
((AutoSuggestView)getPostInput()).setTokenizer(new SpaceTokenizer());
((AutoSuggestView)getPostInput()).setThreshold(2);
((AutoSuggestView)getPostInput()).setRawInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_FLAG_CAP_SENTENCES | InputType.TYPE_TEXT_FLAG_AUTO_CORRECT | InputType.TYPE_TEXT_FLAG_MULTI_LINE);
((AutoSuggestView)getPostInput()).addTextChangedListener(textWatcher);
TListWrapper usernames = CacheManager.getInstance().readFile(Constants.CACHE_AUTOCOMPLETE_USERNAMES, TListWrapper.class);
TListWrapper hashtags = CacheManager.getInstance().readFile(Constants.CACHE_AUTOCOMPLETE_HASHTAGS, TListWrapper.class);
List<AdnModel> newList = new ArrayList<AdnModel>(usernames.getList());
newList.addAll(hashtags.getList());
adapter.setItems(newList);
adapter.notifyDataSetChanged();
}
if (draft != null)
{
getPostInput().setText(draft.getPostText());
setLinkData();
if (getPostInput() instanceof LinkedAutoCompleteTextView)
{
((LinkedAutoCompleteTextView)getPostInput()).setOnSpannableClickedListener(new OnSpannableClickedListener()
{
@Override public void onSpannableClicked(ClickableSpan spannable)
{
if (spannable instanceof MarkDownClickableSpan)
{
handleAnchoredLink((MarkDownClickableSpan)spannable);
}
}
});
}
((EditText)getPostInput()).setSelection(getPostInput().getText().length());
}
if (counter != null)
{
setRemainingChars(maxChars - getPostInput().getText().length());
}
//if (UserManager.getInstance().getLinkedUserIds().size() > 1 && getDraft() != null)
{
User user = UserManager.getInstance().getUser();
if (getDraft() != null)
{
if (TextUtils.isEmpty(getDraft().getSelectedAccountId()))
{
getDraft().setSelectedAccountId(user.getId());
}
else
{
user = User.load(getDraft().getSelectedAccountId());
}
}
actionAccount.setUser(user);
actionAccount.setVisibility(View.VISIBLE);
}
}
public void updateDraft()
{
if (draft != null)
{
if (getPostInput() instanceof EditText)
{
Spannable text = ((EditText)getPostInput()).getText();
MarkDownClickableSpan[] links = text.getSpans(0, text.length(), MarkDownClickableSpan.class);
getDraft().getLinkEntities().clear();
for (MarkDownClickableSpan linkSpan : links)
{
int start = text.getSpanStart(linkSpan);
int end = text.getSpanEnd(linkSpan);
LinkEntity link = new LinkEntity();
link.setPos(start);
link.setLength(end - start);
link.setUrl(linkSpan.getUrl());
if (!linkSpan.getUrl().equals(linkSpan.getAnchor()))
{
try
{
link.setAmendedLength(link.getLength() + Uri.parse(linkSpan.getUrl()).getHost().length() + 3);
}
catch (Exception e)
{
Debug.out(e);
}
}
getDraft().getLinkEntities().add(link);
}
}
getDraft().setPostText(getPostInput().getText().toString());
}
}
public void setLinkData()
{
if (getPostInput() instanceof EditText)
{
SpannableStringBuilder newText = new SpannableStringBuilder(getPostInput().getText());
if (getDraft().getLinkEntities() != null)
{
for (Entity entity : getDraft().getLinkEntities())
{
LinkEntity link = (LinkEntity)entity;
if (link.getAmendedLength() > -1)
{
String anchor = newText.toString().substring(link.getPos(), link.getPos() + link.getLength());
SpannableStringBuilder newLink = new SpannableStringBuilder(anchor);
newLink.setSpan(new MarkDownClickableSpan(link.getUrl(), anchor), 0, anchor.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
newText.replace(link.getPos(), link.getPos() + link.getLength(), newLink);
}
else
{
String anchor = newText.toString().substring(link.getPos(), link.getPos() + link.getLength());
SpannableStringBuilder newLink = new SpannableStringBuilder(anchor);
newLink.setSpan(new MarkDownClickableSpan(link.getUrl(), anchor), 0, link.getLength(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
newText.replace(link.getPos(), link.getPos() + link.getLength(), newLink);
}
}
getPostInput().setText(newText);
}
}
}
public void setRemainingChars(int remaining)
{
counter.setText(String.valueOf(remaining));
if (remaining >= 0)
{
positiveButton.setVisibility(View.VISIBLE);
int colour = 0xCCCCCC;
int progress = 0xFF - (int)(((1f / (float)maxChars) * (float)remaining) * 0xFF);
progress = Math.max(0xCC, progress);
colour = (progress << 16) | (colour & 0x00FFFF);
colour = (0xFF << 24) | (colour & 0x00FFFFFF);
counter.setTextColor(Math.min(0xFFFFCCCC, colour));
}
else
{
positiveButton.setVisibility(View.INVISIBLE);
}
}
public void handleAnchoredLink(final MarkDownClickableSpan spannable)
{
final View view = LayoutInflater.from(getContext()).inflate(R.layout.markdown_link_edit_layout, null, false);
if (spannable != null)
{
((TextView)view.findViewById(R.id.url_anchor)).setText(spannable.getAnchor());
((TextView)view.findViewById(R.id.url)).setText(spannable.getUrl());
((EditText)view.findViewById(R.id.url_anchor)).setSelection(spannable.getAnchor().length());
((EditText)view.findViewById(R.id.url)).setSelection(spannable.getUrl().length());
}
final AlertDialog d = DialogBuilder.create(getContext())
.setTitle(spannable == null ? R.string.add_link : R.string.edit_link)
.setView(view)
.setPositiveButton(R.string.done, null)
.setNegativeButton(R.string.close, new DialogInterface.OnClickListener()
{
@Override public void onClick(DialogInterface dialog, int which)
{
((EditText)getPostInput()).setSelection(getPostInput().getText().length());
}
})
.create();
d.show();
Button button = d.getButton(AlertDialog.BUTTON_POSITIVE);
if (button != null)
{
button.setOnClickListener(new View.OnClickListener()
{
@Override public void onClick(View v)
{
String anchor = ((TextView)view.findViewById(R.id.url_anchor)).getText().toString().trim();
String url = ((TextView)view.findViewById(R.id.url)).getText().toString().trim();
if (!Regex.REGEX_URL.matcher(url).find())
{
Toast.makeText(getContext(), R.string.invalid_url, Toast.LENGTH_LONG).show();
return;
}
SpannableStringBuilder newText = new SpannableStringBuilder(getPostInput().getText());
SpannableStringBuilder newLink = new SpannableStringBuilder(anchor);
newLink.setSpan(new MarkDownClickableSpan(url, anchor), 0, anchor.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
if (spannable == null)
{
if (newText.length() > 0 && newText.charAt(newText.length() - 1) != ' ')
{
newText.append(' ');
}
newText.append(newLink).append(' ');
}
else
{
int start = ((EditText)getPostInput()).getText().getSpanStart(spannable);
int end = ((EditText)getPostInput()).getText().getSpanEnd(spannable);
newText.removeSpan(spannable);
newText.replace(start, end, newLink);
}
((EditText)getPostInput()).setText(newText);
((EditText)getPostInput()).setSelection(getPostInput().getText().length());
d.dismiss();
}
});
}
}
public void addImage(final Uri contentUri)
{
if (!getDraft().getImages().contains(contentUri.toString()))
{
getDraft().getImages().add(contentUri.toString());
addImageToView(contentUri.toString());
}
}
protected void addImageToView(final String imageUrl)
{
View view = LayoutInflater.from(getContext()).inflate(R.layout.post_image_stub, imageContainer, false);
ImageView image = (ImageView)view.findViewById(R.id.image);
ImageLoader.getInstance().displayImage(imageUrl, image);
imageContainer.addView(view);
imageContainer.post(new Runnable()
{
@Override public void run()
{
((HorizontalScrollView)imageContainer.getParent()).smoothScrollTo(imageContainer.getMeasuredWidth(), 0);
}
});
final int position = imageContainer.getChildCount() - 1;
view.setOnClickListener(new View.OnClickListener()
{
@Override public void onClick(View v)
{
new Builder(getContext())
.setTitle(R.string.confirm)
.setMessage(R.string.remove_image)
.setPositiveButton(R.string.yes, new OnClickListener()
{
@Override public void onClick(DialogInterface dialog, int which)
{
getDraft().getImages().remove(imageUrl);
imageContainer.removeViewAt(position);
if (imageContainer.getChildCount() == 0)
{
((View)imageContainer.getParent()).setVisibility(View.GONE);
}
}
})
.setNegativeButton(R.string.no, null)
.show();
}
});
((View)imageContainer.getParent()).setVisibility(View.VISIBLE);
}
@Override public void onPositiveButtonClick(View view)
{
updateDraft();
finish();
}
@Override public void onNegativeButtonClick(View view)
{
updateDraft();
if (finish || TextUtils.isEmpty(getDraft().getPostText()))
{
finish();
return;
}
AlertDialog.Builder builder = DialogBuilder.create(getContext());
builder.setTitle(R.string.confirm);
builder.setMessage(R.string.save_to_drafts);
builder.setPositiveButton(R.string.yes, new OnClickListener()
{
@Override public void onClick(DialogInterface dialog, int which)
{
finish = true;
getDraft().save();
onNegativeButtonClick(null);
}
});
builder.setNegativeButton(R.string.no, new OnClickListener()
{
@Override public void onClick(DialogInterface dialog, int which)
{
finish = true;
onNegativeButtonClick(null);
}
});
builder.setNeutralButton(R.string.cancel, null);
builder.show();
}
public int getAnnotationIndexOfLocation()
{
for (int index = 0, count = getDraft().getAnnotations().size(); index < count; index++)
{
if (getDraft().getAnnotations().get(index) instanceof LocationAnnotation)
{
return index;
}
}
return -1;
}
@OnClick public void onActionLinkClick(View view)
{
handleAnchoredLink(null);
}
@OnClick public void onActionMoreClick(View view)
{
final PopupMenu options = new PopupMenu(this, view);
options.getMenuInflater().inflate(R.menu.menu_post_dialog, options.getMenu());
options.setOnMenuItemClickListener(new OnMenuItemClickListener()
{
@Override public boolean onMenuItemClick(MenuItem menuItem)
{
if (menuItem.getItemId() == R.id.menu_at)
{
getPostInput().append(" @");
}
else if (menuItem.getItemId() == R.id.menu_hash)
{
getPostInput().append(" #");
}
options.dismiss();
return true;
}
});
options.show();
}
@OnClick public void onActionAccountClick(View view)
{
List<String> users = UserManager.getInstance().getLinkedUserIds();
final ArrayList<User> loadedUsers = new ArrayList<User>();
for (int index = 0; index < users.size(); index++)
{
User u = new User().load(users.get(index));
if (u != null)
{
loadedUsers.add(u);
}
}
DialogBuilder.create(getContext())
.setTitle(getString(R.string.select_account))
.setAdapter(new AccountAdapter(getContext(), loadedUsers), new DialogInterface.OnClickListener()
{
@Override public void onClick(DialogInterface dialog, int which)
{
getDraft().setSelectedAccountId(loadedUsers.get(which).getId());
actionAccount.setUser(loadedUsers.get(which));
}
})
.setPositiveButton(R.string.add_account, new OnClickListener()
{
@Override public void onClick(DialogInterface dialog, int which)
{
Intent loginIntent = new Intent(getContext(), AuthenticationActivity.class);
loginIntent.putExtra(Constants.EXTRA_NEW_USER, true);
loginIntent.putExtra(Constants.EXTRA_FINISH, true);
startActivityForResult(loginIntent, Constants.REQUEST_ADD_ACCOUNT);
dialog.dismiss();
}
})
.setNegativeButton(R.string.close, null)
.show();
}
@OnClick public void onActionLocationClick(ImageView view)
{
int index = -1;
if ((index = getAnnotationIndexOfLocation()) > -1)
{
getDraft().getAnnotations().remove(index);
return;
}
getLocationHelper().fetchLocation(10000, Accuracy.FINE, new LocationResponse()
{
@Override public void onRequest()
{
Toast.makeText(getContext(), R.string.fetching_location, Toast.LENGTH_SHORT).show();
}
@Override public void onLocationAcquired(Location l)
{
Toast.makeText(getContext(), R.string.location_aquired, Toast.LENGTH_SHORT).show();
// remove any current location annotations
int index = -1;
if ((index = getAnnotationIndexOfLocation()) > -1)
{
getDraft().getAnnotations().remove(index);
}
LocationAnnotation location = new LocationAnnotation(l);
getDraft().getAnnotations().add(location);
}
@Override public void onTimeout()
{
Location cached = getLocationHelper().getCachedLocation();
if (cached != null)
{
onLocationAcquired(cached);
}
else
{
Toast.makeText(getContext(), R.string.location_failed, Toast.LENGTH_SHORT).show();
}
}
@Override public void onLocationFailed(String message, int messageId)
{
onTimeout();
}
});
}
@OnClick public void onActionImageClick(ImageView view)
{
CharSequence[] items = getResources().getStringArray(R.array.image_choice);
AlertDialog.Builder builder = DialogBuilder.create(getContext());
builder.setItems(items, new DialogInterface.OnClickListener()
{
@Override public void onClick(DialogInterface dialog, int which)
{
// Camera
if (which == 0)
{
File photo = null;
Intent intent = new Intent("android.media.action.IMAGE_CAPTURE");
if (android.os.Environment.getExternalStorageState().equals(android.os.Environment.MEDIA_MOUNTED))
{
String folder = Environment.getExternalStoragePublicDirectory(android.os.Environment.DIRECTORY_DCIM) + "/Camera/";
if (!new File(folder).exists())
{
new File(folder).mkdirs();
}
photo = new File(folder, "robin_" + System.currentTimeMillis() + ".jpg");
}
else
{
photo = new File(getCacheDir(), "robin_" + System.currentTimeMillis() + ".jpg");
}
if (photo != null)
{
tempImagePath = Uri.fromFile(photo);
intent.putExtra(MediaStore.EXTRA_OUTPUT, tempImagePath);
try
{
startActivityForResult(intent, Constants.REQUEST_CAMERA);
}
catch (Exception e)
{
Toast.makeText(getContext(), R.string.camera_failed, Toast.LENGTH_SHORT).show();
}
}
}
// Gallery
else if (which == 1)
{
if (Build.VERSION.SDK_INT < 19)
{
Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
intent.setType("image/jpeg");
startActivityForResult(Intent.createChooser(intent, getString(R.string.select_picture)), Constants.REQUEST_GALLERY);
}
else
{
Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
intent.addCategory(Intent.CATEGORY_OPENABLE);
intent.setType("image/jpeg");
startActivityForResult(Intent.createChooser(intent, getString(R.string.select_picture)), Constants.REQUEST_GALLERY);
}
}
// App.net storage
else if (which == 2)
{
Intent browser = new Intent(getContext(), StorageBrowserActivity.class);
startActivityForResult(browser, Constants.REQUEST_STORAGE);
}
// Last taken photo
else if (which == 3)
{
String[] projection = new String[]{MediaStore.Images.ImageColumns.DATA, MediaStore.Images.ImageColumns.DATE_TAKEN};
Cursor cursor = getContentResolver().query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, projection, null, null, MediaStore.Images.ImageColumns.DATE_TAKEN + " DESC");
if (cursor.moveToFirst())
{
String imageLocation = cursor.getString(0);
File imageFile = new File(imageLocation);
addImage(Uri.fromFile(imageFile));
cursor.close();
}
else
{
Toast.makeText(getContext(), R.string.image_not_found, Toast.LENGTH_SHORT).show();
}
}
}
});
builder.setTitle(getString(R.string.please_select));
builder.show();
}
@Override public void onActivityResult(int requestCode, int resultCode, Intent data)
{
super.onActivityResult(requestCode, resultCode, data);
if (resultCode == RESULT_OK)
{
if (requestCode == Constants.REQUEST_CAMERA)
{
Intent mediaScanIntent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
mediaScanIntent.setData(tempImagePath);
sendBroadcast(mediaScanIntent);
addImage(tempImagePath);
}
else if (requestCode == Constants.REQUEST_GALLERY)
{
if (data != null)
{
Uri selectedUri = data.getData();
if (Build.VERSION.SDK_INT >= 19)
{
final int takeFlags = data.getFlags() & (Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
getContentResolver().takePersistableUriPermission(selectedUri, takeFlags);
}
addImage(selectedUri);
}
}
else if (requestCode == Constants.REQUEST_STORAGE)
{
FileAnnotation file = (FileAnnotation)data.getParcelableExtra(Constants.EXTRA_FILE);
getDraft().getAnnotations().add(file);
addImageToView(file.getThumbUrl());
}
else if (requestCode == Constants.REQUEST_ADD_ACCOUNT)
{
onActionAccountClick(actionAccount);
}
}
}
}